package cn.easyutil.util.javaUtil.http;

import cn.easyutil.util.javaUtil.IOUtil;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.*;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.protocol.HTTP;
import org.apache.http.ssl.SSLContexts;

import javax.net.ssl.SSLContext;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.security.KeyStore;
import java.util.HashMap;
import java.util.Map;

/**
 * 网络请求封装
 */
public class HttpClientOperation extends HttpOperation{

    public HttpClientOperation(){
        super();
    }

    public HttpClientOperation(HttpReq httpReq) {
        super(httpReq);
    }

    public HttpClientOperation(String url) {
        super(url);
    }

    public HttpClientOperation(String url, HttpMethod httpMethod) {
        super(url, httpMethod);
    }

    @Override
    protected HttpRes doUrl(boolean useSSL, HttpReq httpReq, InputStream certInput, char[] password) {
        CloseableHttpClient httpClient = HttpClientBuilder.create().build();
        CloseableHttpResponse response = null;
        HttpEntity httpEntity  = null;
        HttpBaseRequest request = null;
        try {
            //判断是否使用ssl
            if(useSSL){
                KeyStore keyStore = KeyStore.getInstance("PKCS12");
                keyStore.load(certInput, password);
                // mch_id
                SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, password).build();
                // Allow TLSv1 protocol only
                SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext);
                httpClient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
            }

            //创建request请求
            request = new HttpBaseRequest(httpReq.getMethod());
            request.setURI(URI.create(httpReq.getUrl()));
            MultipartEntityBuilder multipartEntityBuilder = MultipartEntityBuilder.create();
            if(httpReq.getFileParams() != null){
                //添加文件参数
                for (HttpFileReq fileParam : httpReq.getFileParams()) {
                    multipartEntityBuilder.addBinaryBody(fileParam.getParamName(), fileParam.getContent(), ContentType.DEFAULT_BINARY,fileParam.getFileName());
                }
            }

            //如果是body体json的，则更换载体
            if(httpReq.getParams().containsKey(HttpReq.nullKeyParam)){
                httpEntity = new StringEntity(httpReq.getParams().get(HttpReq.nullKeyParam).toString(),ContentType.APPLICATION_JSON);
            }else{
                //将参数添加到请求中
                for (Object key : httpReq.getParams().keySet()) {
                    ContentType contentType = ContentType.create(HTTP.CONTENT_TYPE, HTTP.UTF_8);
                    multipartEntityBuilder.addTextBody(key.toString(), httpReq.getParams().get(key).toString(),contentType);
                }
                httpEntity  = multipartEntityBuilder.build();
            }

            //组装添加好的参数
            request.setEntity(httpEntity);

            //添加header头信息
            for (Map.Entry<String, String> entry : httpReq.getHeader().entrySet()) {
                String key = entry.getKey();
                String value = entry.getValue();
                request.addHeader(key, value);
            }

            //添加配置信息
            RequestConfig conf = RequestConfig.custom()
                    .setConnectTimeout(httpReq.getConnectTimeOut())
                    .build();
            request.setConfig(conf);

            //执行请求
            response = httpClient.execute(request);
            return processResponse(response);
        }catch (Exception e) {
            throw new RuntimeException(e);
        }finally {
            try {
                if(httpClient != null){
                    httpClient.close();
                }
                if(response != null){
                    response.close();
                }
                if(certInput != null){
                    certInput.close();
                }
            }catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }

    private HttpRes processResponse(CloseableHttpResponse response){
        HttpRes result = new HttpRes();
        HttpEntity entity = response.getEntity();
        Header[] allHeaders = response.getAllHeaders();
        Map<String,String> headers = new HashMap<>();
        for (Header header : allHeaders) {
            String name = header.getName();
            String value = header.getValue();
            headers.put(name, value);
        }
        result.setResponseHeaders(headers);

        try {
            result.setResponseCode(response.getStatusLine().getStatusCode());
            byte[] bytes = IOUtil.inputToByte(entity.getContent());
            result.setResponseInputStream(IOUtil.byteToInput(bytes));
        } catch (IOException e) {
            e.printStackTrace();
        }

        return result;
    }
}
